package org.example;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

// 切面类 = 切点 + 增强
@Component
@Aspect
public class MyAspect {

    // 前置通知
    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        System.out.println("前置通知");
        System.out.println("连接点 joinPoint = " + joinPoint);
    }

    @Pointcut("execution(* org.example.dao.*.*(..))")
    public void pointcut() {
        System.out.println("切点");
    }

    @Pointcut("execution(* org.example..*Biz.op*(..))")
    public void pointcutOp() {
        System.out.println("切点");
    }

    @After("pointcutOp()")
    public void after(JoinPoint joinPoint) {
        System.out.println("后置通知");
    }

    // 将结果注入到方法参数中, 是Spring DI 的接口注入
    // 注入方式: 接口注入, 构造函数注入, 属性注入
    @AfterReturning(value = "pointcutOp()",returning = "ret")
    public void afterReturning(JoinPoint joinPoint, Object ret) {
        System.out.println("返回通知: " + ret);
    }

    @AfterThrowing(value="pointcutOp()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        System.out.println("异常通知: " + ex);
    }

    @Around("pointcutOp()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 环绕增强特点:
        // 业务方法在增强方法内部手动调用
        // 增强方法的返回结果就是业务方法的返回结果
        try{
            System.out.println("=============== 前置增强");
            long begin = System.currentTimeMillis();
            Object ret = joinPoint.proceed(); // 执行业务方法
            long end = System.currentTimeMillis();
            long time = end - begin;
            System.out.println(joinPoint + "执行时间: " + time);
            System.out.println("=============== 返回增强");
            return ret;
        } catch (Throwable ex) {
            System.out.println("=============== 异常增强");
            throw ex;
        } finally {
            System.out.println("=============== 后置增强");
        }

    }


    /**
     *
     * try {
     *                           前置增强
     *     执行业务方法()
     *                           返回增强
     * } catch ( Ex ...) {
     *                           异常增强
     * } finally {
     *                           后置增强
     * }
     *
     *
     */
}
